--- title: Generating Calibration Files for the OpenHSI Camera keywords: fastai sidebar: home_sidebar summary: "A notebook example for generating settings and calibration files for the OpenHSI camera." description: "A notebook example for generating settings and calibration files for the OpenHSI camera." nb_path: "nbs/10_tutorial_calibrate.ipynb" ---
{% include warning.html content='This is not for genral use. Requires technical expertise.' %} Tools required:
Adjust the camera class as needed. This example uses the LucidCamera.
import os
import holoviews as hv
import numpy as np
from openhsi.calibrate import SettingsBuilderMixin, SpectraPTController, sum_gaussians
from openhsi.cameras import XimeaCameraBase
from openhsi.capture import OpenHSI
hv.extension("bokeh", logo=False)
import panel as pn
class CalibrateCamera(SettingsBuilderMixin, XimeaCameraBase, OpenHSI):
pass
json_path_template = "/xavier_ssd/cals/cam_settings_ximea_template.json"
pkl_path = ""
modelno = 1
print("".format(modelno))
json_path_target = "/xavier_ssd/cals/StarSHOT-HSI-{0:02d}/StarSHOT-HSI-{0:02d}_settings_Mono8_bin1.json".format(
modelno
)
pkl_path_target = "/xavier_ssd/cals/StarSHOT-HSI-{0:02d}/StarSHOT-HSI-{0:02d}_calibration_Mono8_bin1.pkl".format(
modelno
)
if not os.path.isdir(os.path.dirname(json_path_target)):
os.mkdir(os.path.dirname(json_path_target))
spt = SpectraPTController()
The vertical directon/y axis of the detector array corrspeonds the across-track direction of the sensor. If the image of slit is shorter then the heigh we can crop the top and bottom to save bandwidth/disk space (similar to letterboxing video).
There are two ways to do this, croping after the fact using row_minmax or by setting up a window on the sensor. Setting up a window will reduce the ammount of data transfered from the sensor and can improve maximum framerate depending on the sensor so is recomended.
with CalibrateCamera(
json_path=json_path_template, pkl_path="", processing_lvl=-1, exposure_ms=10
) as cam:
hvim_flat = cam.retake_flat_field(show=True)
hvim_flat.opts(width=600, height=600, axiswise=True)
# hvim_row_minmax = cam.update_row_minmax(edgezone=10)
# hvim_row_minmax.opts(width=600, height=600, axiswise=True)
# # Use Row min max to update window
# windowheight = int(
# np.ceil((cam.settings["row_slice"][1] - cam.settings["row_slice"][0]) / 4.0) * 4
# )
# print("Windowheight {}".format(windowheight))
# cam.settings["win_resolution"] = [windowheight + 16, cam.settings["resolution"][1]]
# cam.settings["win_offset"] = [
# int(np.ceil((cam.settings["row_slice"][0]) / 4.0) * 4) - 8,
# cam.settings["win_offset"][1],
# ]
# cam.settings["row_slice"] = [16, windowheight - 8]
cam.settings["resolution"] = cam.settings["win_resolution"]
cam.dump(json_path=json_path_target, pkl_path=pkl_path_target)
# img=cam.crop(cam.calibration["flat_field_pic"])
# hv_flatcrop=hv.Image(img, bounds=(0,0,*img.shape)).opts(xlabel="wavelength index",ylabel="cross-track",cmap="gray",title="test frame",width=400,height=400,axiswise=True)
# spt.selectPreset(1000)
# pn.Column(hvim_row_minmax, hvim_flat)
with CalibrateCamera(
n_lines=50,
processing_lvl=0,
pkl_path=pkl_path_target,
json_path=json_path_target,
exposure_ms=10,
) as cam:
# cam.collect()
cam.start_cam()
img = cam.get_img()
img = cam.crop(img)
cam.stop_cam()
# cam.show(hist_eq=True)
hv.Image(img, bounds=(0, 0, *img.shape)).opts(
xlabel="wavelength index",
ylabel="cross-track",
cmap="gray",
title="test frame",
width=400,
height=400,
)
with CalibrateCamera(
json_path=json_path_target,
pkl_path="",
processing_lvl=-1,
exposure_ms=10
) as cam:
# cam.deviceSettings["Gain"].value = 10.0
hvimg = cam.retake_HgAr(show=True, nframes=18)
# hvimg=hv.Image(cam.crop(cam.calibration["HgAr_pic"]), bounds=(0,0,*cam.calibration["HgAr_pic"].shape)).opts(
# xlabel="wavelength index",ylabel="cross-track",cmap="gray",title="HgAr spectra picture")
hvimg.opts(width=600, height=600)
# print(cam.calibration["HgAr_pic"].max())
# smile_fit_hv = cam.update_smile_shifts()
# # cam.deviceSettings['Gain'].value=15.
# # hvimg=cam.retake_HgAr(show=True,nframes=18)
# cam.calibration["smile_shifts"] = cam.calibration["smile_shifts"] * 0
# wavefit_hv = cam.fit_HgAr_lines(
# top_k=15,
# brightest_peaks=[546.96, 435.833, (579.960 + 579.066) / 2, 763.511],
# find_peaks_height=10,
# prominence=1,
# width=1.5,
# interactive_peak_id=True,
# ) # [435.833,546.074,,763.511]
# # Use wavecal to narrow spetral range.
# waveminmax = [430, 900]
# waveminmax_ind = [
# np.argmin(np.abs(cam.calibration["wavelengths_linear"] - λ)) for λ in waveminmax
# ]
# window_width = int(np.ceil((waveminmax_ind[1] - waveminmax_ind[0] + 8) / 4.0) * 4)
# offset_x = int(np.floor((waveminmax_ind[0] - 4) / 4.0) * 4)
# print("Window Width {}, offset x {}".format(window_width, offset_x))
# cam.settings["win_resolution"][1] = window_width
# cam.settings["win_offset"][1] = offset_x
# cam.settings["resolution"] = cam.settings["win_resolution"]
# pn.Column(
# hvimg,
# smile_fit_hv,
# wavefit_hv.opts(xlim=(390, 1000), ylim=(-10, 255)).opts(shared_axes=False),
# )
hvimg
pn.Column(
hvimg.opts(shared_axes=False),
smile_fit_hv.opts(shared_axes=False),
wavefit_hv.opts(xlim=(400, 900), ylim=(-10, 255)).opts(shared_axes=False),
)
cam.dump(json_path=json_path_target, pkl_path=pkl_path_target)
spt.selectPreset(10000)
with CalibrateCamera(
json_path=json_path_target, pkl_path=pkl_path_target, processing_lvl=-1
) as cam:
hvim_flat = cam.retake_flat_field(show=True)
hvim_flat.opts(width=600, height=600, axiswise=True)
hvim_row_minmax = cam.update_row_minmax(edgezone=8)
hvim_row_minmax.opts(width=600, height=600, axiswise=True)
cam.update_resolution()
cam.dump(json_path=json_path_target, pkl_path=pkl_path_target)
# spt.turnOffLamp()
hvim_row_minmax + hvim_flat
with CalibrateCamera(
json_path=json_path_target, pkl_path=pkl_path_target, processing_lvl=-1
) as cam:
cam.deviceSettings["Gain"].value = 15.0
hvimg = cam.retake_HgAr(show=True)
hvimg.opts(width=400, height=400)
print(cam.calibration["HgAr_pic"].max())
smile_fit_hv = cam.update_smile_shifts()
wavefit_hv = cam.fit_HgAr_lines(
top_k=12,
brightest_peaks=[546.96, 435.833, (579.960 + 579.066) / 2, 871.66, 763.511],
find_peaks_height=10,
prominence=1,
width=1.5,
max_match_error=2,
interactive_peak_id=True,
) # [435.833,546.074,(579.960+579.066)/2,763.511]
cam.update_intsphere_fit()
cam.dump(json_path=json_path_target, pkl_path=pkl_path_target)
(hvimg + smile_fit_hv + wavefit_hv.opts(xlim=(400, 900), ylim=(-10, 255))).opts(
shared_axes=False
)
lum_preset_dict = {
0: 1,
1000: 2,
2000: 3,
3000: 4,
4000: 5,
5000: 6,
6000: 7,
7000: 8,
8000: 9,
9000: 10,
10000: 11,
20000: 12,
25000: 13,
30000: 15,
35000: 15,
40000: 16,
}
lum_preset_dict = {
0: 1,
1000: 2,
2000: 3,
4000: 5,
6000: 7,
8000: 9,
10000: 11,
20000: 12,
40000: 16,
}
luminances = np.fromiter(lum_preset_dict.keys(), dtype=int)
# luminances = np.append(luminances,0)
exposures = [0, 5, 8, 10, 15, 20]
with CalibrateCamera(
json_path=json_path_target, pkl_path=pkl_path_target, processing_lvl=-1
) as cam:
cam.calibration["rad_ref"] = cam.update_intsphere_cube(
exposures, luminances, noframe=50, lum_chg_func=spt.selectPreset
)
# remove saturated images
cam.calibration["rad_ref"] = cam.calibration["rad_ref"].where(
~(
np.sum((cam.calibration["rad_ref"][:, :, :, :, :] == 255), axis=(1, 2))
> 1000
)
)
cam.dump(json_path=json_path_target, pkl_path=pkl_path_target)
spt.turnOffLamp()
cam.calibration["rad_ref"].plot(
y="cross_track", x="wavelength_index", col="exposure", row="luminance", cmap="gray"
)
print("rad_ref is {} MB".format(cam.calibration["rad_ref"].size / 1024 / 1024 * 4))
cam.update_intsphere_fit()
cam.dump(json_path=json_path_target, pkl_path=pkl_path_target)